//    Copyright (C) Clear Office.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Text;
using Office.Spreadsheet.Formats.Biff.Records;

namespace Office.Spreadsheet.Formats.Biff
{
    internal sealed class SstStringReader
    {
        private static readonly Encoding LatinEncoding = Encoding.GetEncoding("latin1");
        private readonly List<BinaryReader> _readers;

        private int _index;
        public bool CanReadString
        {
            get
            {
                if (_index < _readers.Count - 1)
                    return true;
                BinaryReader result = _readers[_index];
                return (result.BaseStream.Length > result.BaseStream.Position);
            }
        }

            public SstStringReader(List<BinaryReader> readers)
        {
            Contract.Requires(readers != null);
            _readers = readers;
        }

        public SharedString ReadString()
        {
            BinaryReader reader = getSafeReader();
            int length = reader.ReadUInt16();
            var flags = (StringInfo)(reader.ReadByte());
           // Debug.WriteLine(length);
            ushort richTextCount = 0;
            if (flags.ContainsRichText)
            {
                richTextCount = reader.ReadUInt16();
            }
            uint asianPhonitecsCount = 0;
            if (flags.ContainsAsianPhonetics)
                asianPhonitecsCount = reader.ReadUInt32();
            string result = readPartialString2(flags.IsUncompressed, length);

            length = length - result.Length;
            while (length > 0)
            {
                _index++;
//                Debug.WriteLine("Switching reader");
                reader = _readers[_index];
                var flags2 = (StringInfo) (reader.ReadByte());
                string toAdd = readPartialString2(flags2.IsUncompressed, length);
                //result += toAdd;
                result = result + toAdd;
                length -= toAdd.Length;
            }
            //Debug.WriteLine(result);
#if STRINGS
            //Debug.WriteLine("reading formatting runs, count = " + richTextCount);
#endif
            var formattingRuns = new List<FormatRun>(readRuns(richTextCount));
            byte [] data = reader.ReadBytes((int) asianPhonitecsCount);
#if DEBUG
            if (data.Length != asianPhonitecsCount)
            {
                reader = this.getSafeReader();
                data = reader.ReadBytes((int) asianPhonitecsCount - data.Length);
            }
#endif
            if (formattingRuns.Count == 0)
                return new SharedString(result);
            return new FormattedString(result, formattingRuns);
        }

        private IEnumerable<FormatRun> readRuns(int count)
        {
            for (int i = 0; i < count; i++)
            {
                BinaryReader reader = getSafeReader();
                var run = new FormatRun(reader);
#if STRINGS
                //\\Debug.WriteLine("yielding " + run);
#endif
                yield return run;
            }
        }

        private BinaryReader getSafeReader()
        {
            BinaryReader result = _readers[_index];
            if (result.BaseStream.Length == result.BaseStream.Position)
            {
                _index++;
                result = _readers[_index];
                //Debug.WriteLine("Getting next reader");
            }
            return result;
        }

        private string readPartialString2(bool isUncompressed, int length)
        {
            BinaryReader reader = _readers[_index];
            string s;
            if (!isUncompressed)
            {
                int actualLength = Math.Min(length, (int) (reader.BaseStream.Length - reader.BaseStream.Position));
                s = LatinEncoding.GetString(reader.ReadBytes(actualLength));
            }
            else
            {
                int actualLength = Math.Min(length*2, (int) (reader.BaseStream.Length - reader.BaseStream.Position));
                s = Encoding.Unicode.GetString(reader.ReadBytes(actualLength));
            }
            return s;
        }

        #region Nested type: AsianPhonetics

        private class AsianPhonetics
        {
            public AsianPhonetics(BinaryReader reader)
            {
                ushort unknown = reader.ReadUInt16();
                ushort ln = reader.ReadUInt16();
            }
        }

        #endregion
    }
}